msg_tool\scripts\bgi\image/
cbg.rs

1//! Buriko General Interpreter/Ethornell Compressed Image File
2use crate::ext::atomic::*;
3use crate::ext::io::*;
4use crate::scripts::base::*;
5use crate::types::*;
6use crate::utils::bit_stream::*;
7use crate::utils::img::*;
8use crate::utils::struct_pack::*;
9use crate::utils::threadpool::*;
10use anyhow::Result;
11use msg_tool_macro::*;
12use std::io::{Read, Seek, Write};
13use std::sync::atomic::AtomicBool;
14use std::sync::{Arc, Mutex};
15
16#[derive(Debug)]
17/// Builder for BGI Compressed Image scripts.
18pub struct BgiCBGBuilder {}
19
20impl BgiCBGBuilder {
21    /// Creates a new instance of `BgiCBGBuilder`.
22    pub const fn new() -> Self {
23        BgiCBGBuilder {}
24    }
25}
26
27impl ScriptBuilder for BgiCBGBuilder {
28    fn default_encoding(&self) -> Encoding {
29        Encoding::Cp932
30    }
31
32    fn build_script(
33        &self,
34        data: Vec<u8>,
35        _filename: &str,
36        _encoding: Encoding,
37        _archive_encoding: Encoding,
38        config: &ExtraConfig,
39        _archive: Option<&Box<dyn Script>>,
40    ) -> Result<Box<dyn Script>> {
41        Ok(Box::new(BgiCBG::new(data, config)?))
42    }
43
44    fn extensions(&self) -> &'static [&'static str] {
45        &[]
46    }
47
48    fn script_type(&self) -> &'static ScriptType {
49        &ScriptType::BGICbg
50    }
51
52    fn is_image(&self) -> bool {
53        true
54    }
55
56    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
57        if buf_len >= 0x10 && buf.starts_with(b"CompressedBG___") {
58            return Some(255);
59        }
60        None
61    }
62
63    fn can_create_image_file(&self) -> bool {
64        true
65    }
66
67    fn create_image_file<'a>(
68        &'a self,
69        data: ImageData,
70        mut writer: Box<dyn WriteSeek + 'a>,
71        _options: &ExtraConfig,
72    ) -> Result<()> {
73        let encoder = CbgEncoder::new(data)?;
74        let data = encoder.encode()?;
75        writer.write_all(&data)?;
76        Ok(())
77    }
78}
79
80#[derive(Debug, StructPack, StructUnpack)]
81struct BgiCBGHeader {
82    width: u16,
83    height: u16,
84    bpp: u32,
85    _unk: u64,
86    intermediate_length: u32,
87    key: u32,
88    enc_length: u32,
89    check_sum: u8,
90    check_xor: u8,
91    version: u16,
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95enum CbgColorType {
96    Bgra32,
97    Bgr24,
98    Grayscale,
99    Bgr565,
100}
101
102fn convert_bgr565_to_bgr24(input: Vec<u8>, width: u16, height: u16) -> ImageData {
103    let pixel_count = width as usize * height as usize;
104    let mut output = Vec::with_capacity(pixel_count * 3);
105
106    for chunk in input.chunks_exact(2) {
107        let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
108
109        let blue_5bit = (pixel & 0x1) as u8;
110        let green_6bit = ((pixel >> 5) & 0x3) as u8;
111        let red_5bit = ((pixel >> 11) & 0x1) as u8;
112
113        let blue = ((blue_5bit as u16 * 255) / 31) as u8;
114        let green = ((green_6bit as u16 * 255) / 63) as u8;
115        let red = ((red_5bit as u16 * 255) / 31) as u8;
116
117        output.push(blue);
118        output.push(green);
119        output.push(red);
120    }
121
122    ImageData {
123        width: width as u32,
124        height: height as u32,
125        color_type: ImageColorType::Bgr,
126        depth: 8,
127        data: output,
128    }
129}
130
131#[derive(Debug)]
132/// BGI Compressed Image script.
133pub struct BgiCBG {
134    header: BgiCBGHeader,
135    data: MemReader,
136    color_type: CbgColorType,
137    decode_workers: usize,
138}
139
140impl BgiCBG {
141    /// Creates a new instance of `BgiCBG` from a buffer.
142    ///
143    /// * `data` - The buffer containing the script data.
144    /// * `config` - Extra configuration options.
145    pub fn new(data: Vec<u8>, config: &ExtraConfig) -> Result<Self> {
146        let mut reader = MemReader::new(data);
147        let mut magic = [0u8; 16];
148        reader.read_exact(&mut magic)?;
149        if !magic.starts_with(b"CompressedBG___") {
150            return Err(anyhow::anyhow!("Invalid magic: {:?}", magic));
151        }
152        let header = BgiCBGHeader::unpack(&mut reader, false, Encoding::Cp932)?;
153        if header.version > 2 {
154            return Err(anyhow::anyhow!("Unsupported version: {}", header.version));
155        }
156        let color_type = match header.bpp {
157            32 => CbgColorType::Bgra32,
158            24 => CbgColorType::Bgr24,
159            8 => CbgColorType::Grayscale,
160            16 => {
161                if header.version == 2 {
162                    return Err(anyhow::anyhow!("Unsupported BPP 16 in version 2"));
163                }
164                CbgColorType::Bgr565
165            }
166            _ => return Err(anyhow::anyhow!("Unsupported BPP: {}", header.bpp)),
167        };
168        Ok(BgiCBG {
169            header,
170            data: reader,
171            color_type,
172            decode_workers: config.bgi_img_workers.max(1),
173        })
174    }
175}
176
177impl Script for BgiCBG {
178    fn default_output_script_type(&self) -> OutputScriptType {
179        OutputScriptType::Json
180    }
181
182    fn default_format_type(&self) -> FormatOptions {
183        FormatOptions::None
184    }
185
186    fn is_image(&self) -> bool {
187        true
188    }
189
190    fn export_image(&self) -> Result<ImageData> {
191        let decoder = CbgDecoder::new(
192            self.data.to_ref(),
193            &self.header,
194            self.color_type,
195            self.decode_workers,
196        )?;
197        Ok(decoder.unpack()?)
198    }
199
200    fn import_image<'a>(
201        &'a self,
202        data: ImageData,
203        mut file: Box<dyn WriteSeek + 'a>,
204    ) -> Result<()> {
205        let encoder = CbgEncoder::new(data)?;
206        let encoded_data = encoder.encode()?;
207        file.write_all(&encoded_data)?;
208        Ok(())
209    }
210}
211
212struct CbgDecoder<'a> {
213    stream: MsbBitStream<MemReaderRef<'a>>,
214    info: &'a BgiCBGHeader,
215    color_type: CbgColorType,
216    key: u32,
217    magic: u32,
218    pixel_size: u8,
219    stride: usize,
220    workers: usize,
221}
222
223impl<'a> CbgDecoder<'a> {
224    fn new(
225        reader: MemReaderRef<'a>,
226        info: &'a BgiCBGHeader,
227        color_type: CbgColorType,
228        workers: usize,
229    ) -> Result<Self> {
230        let magic = 0;
231        let key = info.key;
232        let stream = MsbBitStream::new(reader);
233        let pixel_size = info.bpp as u8 / 8;
234        let stride = info.width as usize * (info.bpp as usize / 8);
235        Ok(CbgDecoder {
236            stream,
237            info,
238            key,
239            magic,
240            color_type,
241            pixel_size,
242            stride,
243            workers,
244        })
245    }
246
247    fn unpack(mut self) -> Result<ImageData> {
248        self.stream.m_input.pos = 0x30;
249        if self.info.version < 2 {
250            return self.unpack_v1();
251        } else if self.info.version == 2 {
252            if self.info.enc_length < 0x80 {
253                return Err(anyhow::anyhow!(
254                    "Invalid encoded length: {}",
255                    self.info.enc_length
256                ));
257            }
258            return self.unpack_v2();
259        }
260        Err(anyhow::anyhow!("Unknown version: {}", self.info.version))
261    }
262
263    fn unpack_v1(&mut self) -> Result<ImageData> {
264        let leaf_nodes_weight = {
265            let stream = MemReader::new(self.read_encoded()?);
266            let mut stream_ref = stream.to_ref();
267            Self::read_weight_table(&mut stream_ref, 0x100)?
268        };
269        let tree = HuffmanTree::new(&leaf_nodes_weight, false);
270        let mut packed = Vec::with_capacity(self.info.intermediate_length as usize);
271        packed.resize(self.info.intermediate_length as usize, 0);
272        self.huffman_decompress(&tree, &mut packed)?;
273        let buf_size = self.stride * self.info.height as usize;
274        let mut output = Vec::with_capacity(buf_size);
275        output.resize(buf_size, 0);
276        Self::unpack_zeros(&packed, &mut output);
277        self.reverse_average_sampling(&mut output);
278        let color_type = match self.color_type {
279            CbgColorType::Bgra32 => ImageColorType::Bgra,
280            CbgColorType::Bgr24 => ImageColorType::Bgr,
281            CbgColorType::Grayscale => ImageColorType::Grayscale,
282            CbgColorType::Bgr565 => {
283                return Ok(convert_bgr565_to_bgr24(
284                    output,
285                    self.info.width,
286                    self.info.height,
287                ));
288            }
289        };
290        Ok(ImageData {
291            width: self.info.width as u32,
292            height: self.info.height as u32,
293            color_type,
294            depth: 8,
295            data: output,
296        })
297    }
298
299    fn unpack_v2(&mut self) -> Result<ImageData> {
300        let dct_data = self.read_encoded()?;
301        let mut dct = [[0.0f32; 64]; 2];
302        for i in 0..0x80 {
303            dct[i >> 6][i & 0x3f] = dct_data[i] as f32 * DCT_TABLE[i & 0x3f];
304        }
305
306        let base_offset = self.stream.m_input.pos;
307        let tree1 = HuffmanTree::new(
308            &Self::read_weight_table(&mut self.stream.m_input, 0x10)?,
309            true,
310        );
311        let tree2 = HuffmanTree::new(
312            &Self::read_weight_table(&mut self.stream.m_input, 0xB0)?,
313            true,
314        );
315
316        let width = ((self.info.width as i32 + 7) & -8) as i32;
317        let height = ((self.info.height as i32 + 7) & -8) as i32;
318        let y_blocks = height / 8;
319
320        let mut offsets = Vec::with_capacity((y_blocks + 1) as usize);
321        let input_base =
322            (self.stream.m_input.pos + ((y_blocks + 1) as usize * 4) - base_offset) as i32;
323
324        for _ in 0..=y_blocks {
325            let offset = self.stream.m_input.read_i32()?;
326            offsets.push(offset - input_base);
327        }
328
329        let input = self.stream.m_input.data[self.stream.m_input.pos..].to_vec();
330        let pad_skip = ((width >> 3) + 7) >> 3;
331
332        let output_size = (width * height * 4) as usize;
333        let output = vec![0u8; output_size];
334        let output_mutex = Mutex::new(output);
335
336        let decoder = Arc::new(ParallelCbgDecoder {
337            input,
338            output: output_mutex,
339            bpp: self.info.bpp as i32,
340            width,
341            height,
342            tree1,
343            tree2,
344            dct,
345            has_alpha: AtomicBool::new(false),
346        });
347
348        let thread_pool = ThreadPool::new(self.workers, Some("cbg-decoder-worker-"), false)?;
349        let mut dst = 0i32;
350
351        for i in 0..y_blocks {
352            let block_offset = offsets[i as usize] + pad_skip;
353            let next_offset = if i + 1 == y_blocks {
354                decoder.input.len() as i32
355            } else {
356                offsets[(i + 1) as usize]
357            };
358            let closure_dst = dst;
359            let decoder_ref = Arc::clone(&decoder);
360
361            thread_pool.execute(
362                move |_| {
363                    decoder_ref.unpack_block(block_offset, next_offset - block_offset, closure_dst)
364                },
365                true,
366            )?;
367            dst += width * 32;
368        }
369
370        if self.info.bpp == 32 {
371            let decoder_ref = Arc::clone(&decoder);
372            thread_pool.execute(
373                move |_| decoder_ref.unpack_alpha(offsets[y_blocks as usize]),
374                true,
375            )?;
376        }
377
378        let tasks = thread_pool.into_results();
379
380        for task in tasks {
381            task?;
382        }
383
384        let has_alpha = decoder.has_alpha.qload();
385        let mut output = decoder
386            .output
387            .lock()
388            .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?
389            .clone();
390
391        if !has_alpha {
392            let mut src_idx = 0;
393            let mut dst_idx = 0;
394            for _ in 0..self.info.height {
395                for _ in 0..self.info.width {
396                    output[dst_idx] = output[src_idx];
397                    output[dst_idx + 1] = output[src_idx + 1];
398                    output[dst_idx + 2] = output[src_idx + 2];
399                    src_idx += 4;
400                    dst_idx += 3;
401                }
402            }
403            output.truncate(dst_idx);
404        }
405
406        let color_type = if has_alpha {
407            ImageColorType::Bgra
408        } else {
409            ImageColorType::Bgr
410        };
411
412        let img = ImageData {
413            width: decoder.width as u32,
414            height: decoder.height as u32,
415            color_type,
416            depth: 8,
417            data: output,
418        };
419
420        if decoder.width != self.info.width as i32 || decoder.height != self.info.height as i32 {
421            return Ok(draw_on_canvas(
422                img,
423                self.info.width as u32,
424                self.info.height as u32,
425                0,
426                0,
427            )?);
428        }
429
430        Ok(img)
431    }
432
433    fn read_encoded(&mut self) -> Result<Vec<u8>> {
434        let mut output = Vec::with_capacity(self.info.enc_length as usize);
435        output.resize(self.info.enc_length as usize, 0);
436        self.stream.m_input.read_exact(&mut output)?;
437        let mut sum = 0u8;
438        let mut xor = 0u8;
439        for i in 0..output.len() {
440            output[i] = output[i].wrapping_sub(self.update_key());
441            sum = sum.wrapping_add(output[i]);
442            xor ^= output[i];
443        }
444        if sum != self.info.check_sum || xor != self.info.check_xor {
445            return Err(anyhow::anyhow!(
446                "Checksum mismatch: sum={}, xor={}",
447                sum,
448                xor
449            ));
450        }
451        Ok(output)
452    }
453
454    fn read_int(input: &mut MemReaderRef<'_>) -> Result<i32> {
455        let mut v = 0;
456        let mut code_length = 0;
457        loop {
458            let code = input.read_i8()?;
459            if code_length >= 32 {
460                return Err(anyhow::anyhow!(
461                    "Failed to raed int: code={}, code_length={}",
462                    code,
463                    code_length
464                ));
465            }
466            v |= ((code & 0x7f) as i32) << code_length;
467            code_length += 7;
468            if code & -128 == 0 {
469                break;
470            }
471        }
472        Ok(v)
473    }
474
475    fn read_weight_table(input: &mut MemReaderRef<'_>, length: usize) -> Result<Vec<u32>> {
476        let mut weights = Vec::with_capacity(length);
477        for _ in 0..length {
478            let weight = Self::read_int(input)? as u32;
479            weights.push(weight);
480        }
481        Ok(weights)
482    }
483
484    fn huffman_decompress(&mut self, tree: &HuffmanTree, output: &mut [u8]) -> Result<()> {
485        for dst in 0..output.len() {
486            output[dst] = tree.decode_token(&mut self.stream)? as u8;
487        }
488        Ok(())
489    }
490
491    fn unpack_zeros(input: &[u8], output: &mut [u8]) {
492        let mut dst = 0;
493        let mut dec_zero = 0;
494        let mut src = 0;
495        while dst < output.len() {
496            let mut code_length = 0;
497            let mut count = 0;
498            let mut code;
499            loop {
500                if src >= input.len() {
501                    return;
502                }
503                code = input[src];
504                src += 1;
505                count |= ((code & 0x7f) as usize) << code_length;
506                code_length += 7;
507                if code & 0x80 == 0 {
508                    break;
509                }
510            }
511            if dst + count > output.len() {
512                break;
513            }
514            if dec_zero == 0 {
515                if src + count > input.len() {
516                    break;
517                }
518                output[dst..dst + count].copy_from_slice(&input[src..src + count]);
519                src += count;
520            } else {
521                for i in 0..count {
522                    output[dst + i] = 0;
523                }
524            }
525            dec_zero ^= 1;
526            dst += count;
527        }
528    }
529
530    fn reverse_average_sampling(&self, output: &mut [u8]) {
531        for y in 0..self.info.height {
532            let line = y as usize * self.stride;
533            for x in 0..self.info.width {
534                let pixel = line + x as usize * self.pixel_size as usize;
535                for p in 0..self.pixel_size {
536                    let mut avg = 0u32;
537                    if x > 0 {
538                        avg = avg.wrapping_add(
539                            output[pixel + p as usize - self.pixel_size as usize] as u32,
540                        );
541                    }
542                    if y > 0 {
543                        avg = avg.wrapping_add(output[pixel + p as usize - self.stride] as u32);
544                    }
545                    if x > 0 && y > 0 {
546                        avg /= 2;
547                    }
548                    if avg != 0 {
549                        output[pixel + p as usize] =
550                            output[pixel + p as usize].wrapping_add(avg as u8);
551                    }
552                }
553            }
554        }
555    }
556
557    fn update_key(&mut self) -> u8 {
558        let v0 = 20021 * (self.key & 0xffff);
559        let mut v1 = self.magic | (self.key >> 16);
560        v1 = v1
561            .overflowing_mul(20021)
562            .0
563            .overflowing_add(self.key.overflowing_mul(346).0)
564            .0;
565        v1 = (v1 + (v0 >> 16)) & 0xffff;
566        self.key = (v1 << 16) + (v0 & 0xffff) + 1;
567        v1 as u8
568    }
569}
570
571#[derive(Debug)]
572struct HuffmanNode {
573    valid: bool,
574    is_parent: bool,
575    weight: u32,
576    left_index: usize,
577    right_index: usize,
578}
579
580#[derive(Debug)]
581struct HuffmanTree {
582    nodes: Vec<HuffmanNode>,
583}
584
585impl HuffmanTree {
586    fn new(weights: &[u32], v2: bool) -> Self {
587        let mut nodes = Vec::with_capacity(weights.len() * 2);
588        let mut root_node_weight = 0u32;
589        for weight in weights {
590            let node = HuffmanNode {
591                valid: *weight != 0,
592                is_parent: false,
593                weight: *weight,
594                left_index: 0,
595                right_index: 0,
596            };
597            nodes.push(node);
598            root_node_weight = root_node_weight.wrapping_add(*weight);
599        }
600        let mut child_node_index = [0usize; 2];
601        loop {
602            let mut weight = 0u32;
603            for i in 0usize..2usize {
604                let mut min_weight = u32::MAX;
605                child_node_index[i] = usize::MAX;
606                let mut n = 0;
607                if v2 {
608                    while n < nodes.len() {
609                        if nodes[n].valid {
610                            min_weight = nodes[n].weight;
611                            child_node_index[i] = n;
612                            n += 1;
613                            break;
614                        }
615                        n += 1;
616                    }
617                    n = n.max(i + 1);
618                }
619                while n < nodes.len() {
620                    if nodes[n].valid && nodes[n].weight < min_weight {
621                        min_weight = nodes[n].weight;
622                        child_node_index[i] = n;
623                    }
624                    n += 1;
625                }
626                if child_node_index[i] == usize::MAX {
627                    continue;
628                }
629                nodes[child_node_index[i]].valid = false;
630                weight = weight.wrapping_add(nodes[child_node_index[i]].weight);
631            }
632            let parent_node = HuffmanNode {
633                valid: true,
634                is_parent: true,
635                left_index: child_node_index[0],
636                right_index: child_node_index[1],
637                weight,
638            };
639            nodes.push(parent_node);
640            if weight >= root_node_weight {
641                break;
642            }
643        }
644        Self { nodes }
645    }
646
647    fn decode_token(&self, stream: &mut MsbBitStream<MemReaderRef<'_>>) -> Result<usize> {
648        let mut node_index = self.nodes.len() - 1;
649        loop {
650            let bit = stream.get_next_bit()?;
651            if !bit {
652                node_index = self.nodes[node_index].left_index;
653            } else {
654                node_index = self.nodes[node_index].right_index;
655            }
656            if !self.nodes[node_index].is_parent {
657                return Ok(node_index);
658            }
659        }
660    }
661
662    fn encode_token(&self, stream: &mut MsbBitWriter<impl Write>, token: usize) -> Result<()> {
663        let mut path = Vec::new();
664        if !self.find_path(self.nodes.len() - 1, token, &mut path) {
665            return Err(anyhow::anyhow!("Token not found in Huffman tree"));
666        }
667        for &bit in path.iter().rev() {
668            stream.put_bit(bit)?;
669        }
670        Ok(())
671    }
672
673    fn find_path(&self, node_index: usize, token: usize, path: &mut Vec<bool>) -> bool {
674        if node_index == usize::MAX {
675            return false;
676        }
677        let node = &self.nodes[node_index];
678        if !node.is_parent {
679            return node_index == token;
680        }
681
682        if self.find_path(node.left_index, token, path) {
683            path.push(false);
684            return true;
685        }
686        if self.find_path(node.right_index, token, path) {
687            path.push(true);
688            return true;
689        }
690        false
691    }
692}
693
694const DCT_TABLE: [f32; 64] = [
695    1.00000000, 1.38703990, 1.30656302, 1.17587554, 1.00000000, 0.78569496, 0.54119611, 0.27589938,
696    1.38703990, 1.92387950, 1.81225491, 1.63098633, 1.38703990, 1.08979023, 0.75066054, 0.38268343,
697    1.30656302, 1.81225491, 1.70710683, 1.53635550, 1.30656302, 1.02655995, 0.70710677, 0.36047992,
698    1.17587554, 1.63098633, 1.53635550, 1.38268340, 1.17587554, 0.92387950, 0.63637930, 0.32442334,
699    1.00000000, 1.38703990, 1.30656302, 1.17587554, 1.00000000, 0.78569496, 0.54119611, 0.27589938,
700    0.78569496, 1.08979023, 1.02655995, 0.92387950, 0.78569496, 0.61731654, 0.42521504, 0.21677275,
701    0.54119611, 0.75066054, 0.70710677, 0.63637930, 0.54119611, 0.42521504, 0.29289323, 0.14931567,
702    0.27589938, 0.38268343, 0.36047992, 0.32442334, 0.27589938, 0.21677275, 0.14931567, 0.07612047,
703];
704
705const BLOCK_FILL_ORDER: [u8; 64] = [
706    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
707    13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
708    52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
709];
710
711struct ParallelCbgDecoder {
712    input: Vec<u8>,
713    output: Mutex<Vec<u8>>,
714    bpp: i32,
715    width: i32,
716    height: i32,
717    tree1: HuffmanTree,
718    tree2: HuffmanTree,
719    dct: [[f32; 64]; 2],
720    has_alpha: AtomicBool,
721}
722
723impl ParallelCbgDecoder {
724    fn unpack_block(&self, offset: i32, length: i32, dst: i32) -> Result<()> {
725        let input = MemReaderRef::new(&self.input[offset as usize..(offset + length) as usize]);
726        let mut reader = MsbBitStream::new(input);
727
728        let block_size = CbgDecoder::read_int(&mut reader.m_input)?;
729        if block_size == -1 {
730            return Ok(());
731        }
732
733        let mut color_data = vec![0i16; block_size as usize];
734        let mut acc = 0i32;
735        let mut i = 0i32;
736
737        while i < block_size && reader.m_input.pos < reader.m_input.data.len() {
738            let count = self.tree1.decode_token(&mut reader)?;
739            if count != 0 {
740                let mut v = reader.get_bits(count as u32)? as i32;
741                if (v >> (count - 1)) == 0 {
742                    v = (-1 << count | v) + 1;
743                }
744                acc += v;
745            }
746            color_data[i as usize] = acc as i16;
747            i += 64;
748        }
749
750        if (reader.m_cached_bits & 7) != 0 {
751            reader.get_bits(reader.m_cached_bits & 7)?;
752        }
753
754        i = 0;
755        while i < block_size && reader.m_input.pos < reader.m_input.data.len() {
756            let mut index = 1usize;
757            while index < 64 && reader.m_input.pos < reader.m_input.data.len() {
758                let code = self.tree2.decode_token(&mut reader)?;
759                if code == 0 {
760                    break;
761                }
762                if code == 0xf {
763                    index += 0x10;
764                    continue;
765                }
766                index += code & 0xf;
767                if index >= BLOCK_FILL_ORDER.len() {
768                    break;
769                }
770                let bits = code >> 4;
771                let mut v = reader.get_bits(bits as u32)? as i32;
772                if bits != 0 && (v >> (bits - 1)) == 0 {
773                    v = (-1 << bits | v) + 1;
774                }
775                color_data[i as usize + BLOCK_FILL_ORDER[index] as usize] = v as i16;
776                index += 1;
777            }
778            i += 64;
779        }
780
781        if self.bpp == 8 {
782            self.decode_grayscale(&color_data, dst)?;
783        } else {
784            self.decode_rgb(&color_data, dst)?;
785        }
786
787        Ok(())
788    }
789
790    fn decode_rgb(&self, data: &[i16], dst: i32) -> Result<()> {
791        let block_count = self.width / 8;
792        let mut dst = dst as usize;
793
794        for i in 0..block_count {
795            let mut src = (i * 64) as usize;
796            let mut ycbcr_block = [[0i16; 3]; 64];
797
798            for channel in 0..3 {
799                self.decode_dct(channel, data, src, &mut ycbcr_block)?;
800                src += (self.width * 8) as usize;
801            }
802
803            let mut output = self
804                .output
805                .lock()
806                .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
807
808            for j in 0..64 {
809                let cy = ycbcr_block[j][0] as f32;
810                let cb = ycbcr_block[j][1] as f32;
811                let cr = ycbcr_block[j][2] as f32;
812
813                // Full-range YCbCr->RGB conversion
814                let r = cy + 1.402f32 * cr - 178.956f32;
815                let g = cy - 0.34414f32 * cb - 0.71414f32 * cr + 135.95984f32;
816                let b = cy + 1.772f32 * cb - 226.316f32;
817
818                let y = j >> 3;
819                let x = j & 7;
820                let p = (y * self.width as usize + x) * 4 + dst;
821
822                output[p] = Self::float_to_byte(b);
823                output[p + 1] = Self::float_to_byte(g);
824                output[p + 2] = Self::float_to_byte(r);
825            }
826            dst += 32;
827        }
828        Ok(())
829    }
830
831    fn decode_grayscale(&self, data: &[i16], dst: i32) -> Result<()> {
832        let mut src = 0;
833        let block_count = self.width / 8;
834        let mut dst = dst as usize;
835
836        for _ in 0..block_count {
837            let mut ycbcr_block = [[0i16; 3]; 64];
838            self.decode_dct(0, data, src, &mut ycbcr_block)?;
839            src += 64;
840
841            let mut output = self
842                .output
843                .lock()
844                .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
845
846            for j in 0..64 {
847                let y = j >> 3;
848                let x = j & 7;
849                let p = (y * self.width as usize + x) * 4 + dst;
850                let value = ycbcr_block[j][0] as u8;
851
852                output[p] = value;
853                output[p + 1] = value;
854                output[p + 2] = value;
855            }
856            dst += 32;
857        }
858        Ok(())
859    }
860
861    fn unpack_alpha(&self, offset: i32) -> Result<()> {
862        let mut input = MemReaderRef::new(&self.input[offset as usize..]);
863
864        if input.read_i32()? != 1 {
865            return Ok(());
866        }
867
868        let mut dst = 3;
869        let mut ctl = 1i32 << 1;
870
871        let mut output = self
872            .output
873            .lock()
874            .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
875
876        while dst < output.len() {
877            ctl >>= 1;
878            if ctl == 1 {
879                ctl = (input.read_u8()? as i32) | 0x100;
880            }
881
882            if (ctl & 1) != 0 {
883                let v = input.read_u16()? as i32;
884                let mut x = v & 0x3f;
885                if x > 0x1f {
886                    x |= -0x40;
887                }
888                let mut y = (v >> 6) & 7;
889                if y != 0 {
890                    y |= -8;
891                }
892                let count = ((v >> 9) & 0x7f) + 3;
893
894                let src = dst as isize + (x as isize + y as isize * self.width as isize) * 4;
895                if src < 0 || src >= dst as isize {
896                    return Ok(());
897                }
898
899                let mut src = src as usize;
900                for _ in 0..count {
901                    output[dst] = output[src];
902                    src += 4;
903                    dst += 4;
904                }
905            } else {
906                output[dst] = input.read_u8()?;
907                dst += 4;
908            }
909        }
910
911        self.has_alpha.qsave(true);
912        Ok(())
913    }
914
915    fn decode_dct(
916        &self,
917        channel: usize,
918        data: &[i16],
919        src: usize,
920        output: &mut [[i16; 3]; 64],
921    ) -> Result<()> {
922        let d = if channel > 0 { 1 } else { 0 };
923        let mut tmp = [[0f32; 8]; 8];
924
925        for i in 0..8 {
926            // Check if all AC coefficients are zero
927            if data[src + 8 + i] == 0
928                && data[src + 16 + i] == 0
929                && data[src + 24 + i] == 0
930                && data[src + 32 + i] == 0
931                && data[src + 40 + i] == 0
932                && data[src + 48 + i] == 0
933                && data[src + 56 + i] == 0
934            {
935                let t = data[src + i] as f32 * self.dct[d][i];
936                for row in 0..8 {
937                    tmp[row][i] = t;
938                }
939                continue;
940            }
941
942            let v1 = data[src + i] as f32 * self.dct[d][i];
943            let v2 = data[src + 8 + i] as f32 * self.dct[d][8 + i];
944            let v3 = data[src + 16 + i] as f32 * self.dct[d][16 + i];
945            let v4 = data[src + 24 + i] as f32 * self.dct[d][24 + i];
946            let v5 = data[src + 32 + i] as f32 * self.dct[d][32 + i];
947            let v6 = data[src + 40 + i] as f32 * self.dct[d][40 + i];
948            let v7 = data[src + 48 + i] as f32 * self.dct[d][48 + i];
949            let v8 = data[src + 56 + i] as f32 * self.dct[d][56 + i];
950
951            let v10 = v1 + v5;
952            let v11 = v1 - v5;
953            let v12 = v3 + v7;
954            let v13 = (v3 - v7) * 1.414213562f32 - v12;
955            let v1 = v10 + v12;
956            let v7 = v10 - v12;
957            let v3 = v11 + v13;
958            let v5 = v11 - v13;
959            let v14 = v2 + v8;
960            let v15 = v2 - v8;
961            let v16 = v6 + v4;
962            let v17 = v6 - v4;
963            let v8 = v14 + v16;
964            let v11 = (v14 - v16) * 1.414213562f32;
965            let v9 = (v17 + v15) * 1.847759065f32;
966            let v10 = 1.082392200f32 * v15 - v9;
967            let v13 = -2.613125930f32 * v17 + v9;
968            let v6 = v13 - v8;
969            let v4 = v11 - v6;
970            let v2 = v10 + v4;
971
972            tmp[0][i] = v1 + v8;
973            tmp[1][i] = v3 + v6;
974            tmp[2][i] = v5 + v4;
975            tmp[3][i] = v7 - v2;
976            tmp[4][i] = v7 + v2;
977            tmp[5][i] = v5 - v4;
978            tmp[6][i] = v3 - v6;
979            tmp[7][i] = v1 - v8;
980        }
981
982        let mut dst = 0;
983        for i in 0..8 {
984            let v10 = tmp[i][0] + tmp[i][4];
985            let v11 = tmp[i][0] - tmp[i][4];
986            let v12 = tmp[i][2] + tmp[i][6];
987            let v13 = tmp[i][2] - tmp[i][6];
988            let v14 = tmp[i][1] + tmp[i][7];
989            let v15 = tmp[i][1] - tmp[i][7];
990            let v16 = tmp[i][5] + tmp[i][3];
991            let v17 = tmp[i][5] - tmp[i][3];
992
993            let v13 = 1.414213562f32 * v13 - v12;
994            let v1 = v10 + v12;
995            let v7 = v10 - v12;
996            let v3 = v11 + v13;
997            let v5 = v11 - v13;
998            let v8 = v14 + v16;
999            let v11 = (v14 - v16) * 1.414213562f32;
1000            let v9 = (v17 + v15) * 1.847759065f32;
1001            let v10 = v9 - v15 * 1.082392200f32;
1002            let v13 = v9 - v17 * 2.613125930f32;
1003            let v6 = v13 - v8;
1004            let v4 = v11 - v6;
1005            let v2 = v10 - v4;
1006
1007            output[dst][channel] = Self::float_to_short(v1 + v8);
1008            output[dst + 1][channel] = Self::float_to_short(v3 + v6);
1009            output[dst + 2][channel] = Self::float_to_short(v5 + v4);
1010            output[dst + 3][channel] = Self::float_to_short(v7 + v2);
1011            output[dst + 4][channel] = Self::float_to_short(v7 - v2);
1012            output[dst + 5][channel] = Self::float_to_short(v5 - v4);
1013            output[dst + 6][channel] = Self::float_to_short(v3 - v6);
1014            output[dst + 7][channel] = Self::float_to_short(v1 - v8);
1015            dst += 8;
1016        }
1017
1018        Ok(())
1019    }
1020
1021    fn float_to_short(f: f32) -> i16 {
1022        let a = 0x80 + ((f as i32) >> 3);
1023        if a <= 0 {
1024            0
1025        } else if a <= 0xff {
1026            a as i16
1027        } else if a < 0x180 {
1028            0xff
1029        } else {
1030            0
1031        }
1032    }
1033
1034    fn float_to_byte(f: f32) -> u8 {
1035        if f >= 255.0 {
1036            0xff
1037        } else if f <= 0.0 {
1038            0
1039        } else {
1040            f as u8
1041        }
1042    }
1043}
1044
1045struct CbgEncoder {
1046    header: BgiCBGHeader,
1047    stream: MemWriter,
1048    img: ImageData,
1049    key: u32,
1050    magic: u32,
1051}
1052
1053impl CbgEncoder {
1054    pub fn new(mut img: ImageData) -> Result<Self> {
1055        if img.depth != 8 {
1056            return Err(anyhow::anyhow!("Unsupported image depth: {}", img.depth));
1057        }
1058        let bpp = match img.color_type {
1059            ImageColorType::Bgr => 24,
1060            ImageColorType::Bgra => 32,
1061            ImageColorType::Grayscale => 8,
1062            ImageColorType::Rgb => {
1063                convert_rgb_to_bgr(&mut img)?;
1064                24
1065            }
1066            ImageColorType::Rgba => {
1067                convert_rgba_to_bgra(&mut img)?;
1068                32
1069            }
1070        };
1071        let key = rand::random();
1072        let header = BgiCBGHeader {
1073            width: img.width as u16,
1074            height: img.height as u16,
1075            bpp,
1076            _unk: 0,
1077            intermediate_length: 0,
1078            key,
1079            enc_length: 0,
1080            check_sum: 0,
1081            check_xor: 0,
1082            version: 1,
1083        };
1084
1085        Ok(CbgEncoder {
1086            header,
1087            stream: MemWriter::new(),
1088            img,
1089            key,
1090            magic: 0,
1091        })
1092    }
1093
1094    pub fn encode(mut self) -> Result<Vec<u8>> {
1095        self.stream.write_all(b"CompressedBG___\0")?;
1096        let header_pos = self.stream.pos;
1097        self.stream.seek(std::io::SeekFrom::Current(0x20))?;
1098
1099        let pixel_size = (self.header.bpp / 8) as usize;
1100        let stride = self.header.width as usize * pixel_size;
1101        let mut sampled_data = self.img.data.clone();
1102        self.average_sampling(&mut sampled_data, stride, pixel_size);
1103
1104        let packed_data = Self::pack_zeros(&sampled_data);
1105        self.header.intermediate_length = packed_data.len() as u32;
1106
1107        let mut frequencies = vec![0u32; 256];
1108        for &byte in &packed_data {
1109            frequencies[byte as usize] += 1;
1110        }
1111        if frequencies.iter().all(|&f| f == 0) {
1112            frequencies[0] = 1;
1113        }
1114
1115        let tree = HuffmanTree::new(&frequencies, false);
1116
1117        let mut weight_writer = MemWriter::new();
1118        for &weight in &frequencies {
1119            Self::write_int(&mut weight_writer, weight as i32)?;
1120        }
1121        let weight_data = weight_writer.into_inner();
1122        self.write_encoded(&weight_data)?;
1123
1124        let mut bit_writer = MsbBitWriter::new(&mut self.stream);
1125        for &byte in &packed_data {
1126            tree.encode_token(&mut bit_writer, byte as usize)?;
1127        }
1128        bit_writer.flush()?;
1129
1130        let final_pos = self.stream.pos;
1131        self.stream.pos = header_pos;
1132        self.header.pack(&mut self.stream, false, Encoding::Cp932)?;
1133        self.stream.pos = final_pos;
1134
1135        Ok(self.stream.into_inner())
1136    }
1137
1138    fn average_sampling(&self, data: &mut [u8], stride: usize, pixel_size: usize) {
1139        for y in (0..self.header.height as usize).rev() {
1140            let line = y * stride;
1141            for x in (0..self.header.width as usize).rev() {
1142                let pixel = line + x * pixel_size;
1143                for p in 0..pixel_size {
1144                    let mut avg = 0u32;
1145                    let mut count = 0;
1146                    if x > 0 {
1147                        avg = avg.wrapping_add(data[pixel + p - pixel_size] as u32);
1148                        count += 1;
1149                    }
1150                    if y > 0 {
1151                        avg = avg.wrapping_add(data[pixel + p - stride] as u32);
1152                        count += 1;
1153                    }
1154                    if count > 0 {
1155                        avg /= count;
1156                    }
1157                    if avg != 0 {
1158                        data[pixel + p] = data[pixel + p].wrapping_sub(avg as u8);
1159                    }
1160                }
1161            }
1162        }
1163    }
1164
1165    fn pack_zeros(input: &[u8]) -> Vec<u8> {
1166        let mut output = Vec::new();
1167        let mut i = 0;
1168        let mut is_zero_run = false;
1169
1170        while i < input.len() {
1171            let mut count = 0;
1172            if is_zero_run {
1173                while i + count < input.len() && input[i + count] == 0 {
1174                    count += 1;
1175                }
1176            } else {
1177                while i + count < input.len() && input[i + count] != 0 {
1178                    count += 1;
1179                }
1180            }
1181
1182            let mut count_buf = Vec::new();
1183            let mut n = count;
1184            loop {
1185                let mut byte = (n & 0x7f) as u8;
1186                n >>= 7;
1187                if n > 0 {
1188                    byte |= 0x80;
1189                }
1190                count_buf.push(byte);
1191                if n == 0 {
1192                    break;
1193                }
1194            }
1195            output.extend_from_slice(&count_buf);
1196
1197            if !is_zero_run {
1198                output.extend_from_slice(&input[i..i + count]);
1199            }
1200            i += count;
1201            is_zero_run = !is_zero_run;
1202        }
1203        output
1204    }
1205
1206    fn write_int<W: Write>(writer: &mut W, mut value: i32) -> Result<()> {
1207        loop {
1208            let mut b = (value as u8) & 0x7f;
1209            value >>= 7;
1210            if value != 0 {
1211                b |= 0x80;
1212            }
1213            writer.write_u8(b)?;
1214            if value == 0 {
1215                break;
1216            }
1217        }
1218        Ok(())
1219    }
1220
1221    fn write_encoded(&mut self, data: &[u8]) -> Result<()> {
1222        self.header.enc_length = data.len() as u32;
1223        let mut sum = 0u8;
1224        let mut xor = 0u8;
1225        let mut encoded_data = Vec::with_capacity(data.len());
1226        for &byte in data {
1227            let encrypted_byte = byte.wrapping_add(self.update_key());
1228            sum = sum.wrapping_add(byte);
1229            xor ^= byte;
1230            encoded_data.push(encrypted_byte);
1231        }
1232        self.header.check_sum = sum;
1233        self.header.check_xor = xor;
1234        self.stream.write_all(&encoded_data)?;
1235        Ok(())
1236    }
1237
1238    fn update_key(&mut self) -> u8 {
1239        let v0 = 20021 * (self.key & 0xffff);
1240        let mut v1 = self.magic | (self.key >> 16);
1241        v1 = v1
1242            .overflowing_mul(20021)
1243            .0
1244            .overflowing_add(self.key.overflowing_mul(346).0)
1245            .0;
1246        v1 = (v1 + (v0 >> 16)) & 0xffff;
1247        self.key = (v1 << 16) + (v0 & 0xffff) + 1;
1248        v1 as u8
1249    }
1250}